package vip.xiaomaoxiaoke.joinbymemory.support;

import vip.xiaomaoxiaoke.joinbymemory.JoinItemsExecutor;
import vip.xiaomaoxiaoke.joinbymemory.JoinItemsExecutorFactory;
import vip.xiaomaoxiaoke.joinbymemory.JoinService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentMap;

/**
 * 重构版 DefaultJoinService
 * <p>
 * 功能：
 * - 支持注解驱动的内存关联填充
 * - 执行器缓存（避免重复反射扫描）
 * - 防止循环依赖（支持嵌套调用）
 * - 支持分组（group）执行
 * - 线程安全 + Inheritable 支持异步/线程池
 * - 无内存泄漏（finally 清理）
 *
 * @param <T> 数据类型
 */
@Slf4j
public class DefaultJoinService implements JoinService {

    private final JoinItemsExecutorFactory joinItemsExecutorFactory;

    /**
     * 缓存：Class + group -> JoinItemsExecutor
     * 使用类名（String）避免类加载器问题
     */
    private final ConcurrentMap<CacheKey, JoinItemsExecutor> cache = Maps.newConcurrentMap();

    /**
     * 当前线程的调用栈（用于检测循环依赖）
     * key: 正在处理的类的全限定名
     * 使用 InheritableThreadLocal 支持线程池/异步调用
     */
    private static final ThreadLocal<Set<String>> CALL_STACK = new InheritableThreadLocal<>();

    /**
     * 当前线程的 group 上下文（嵌套调用时传递 group）
     */
    private static final ThreadLocal<String> GROUP_CONTEXT = new InheritableThreadLocal<>();

    public DefaultJoinService(JoinItemsExecutorFactory joinItemsExecutorFactory) {
        this.joinItemsExecutorFactory = Objects.requireNonNull(joinItemsExecutorFactory, "joinItemsExecutorFactory cannot be null");
    }

    @Override
    public <T> void joinByMemory(Class<T> targetClass, List<T> data, String group) {
        if (targetClass == null) {
            throw new IllegalArgumentException("targetClass cannot be null");
        }
        if (data == null || data.isEmpty()) {
            log.debug("No data to join for class: {}, group: {}", targetClass.getSimpleName(), group);
            return;
        }

        // 使用传入的 group，若为空则使用上下文
        String effectiveGroup = group != null ? group : GROUP_CONTEXT.get();
        log.debug("Starting joinByMemory for class: {}, group: {}, data size: {}", targetClass.getSimpleName(), effectiveGroup, data.size());

        // === 上下文管理 ===
        Set<String> callStack = CALL_STACK.get();
        boolean isFirstInvocation = false; // 标记是否是本次调用链的入口

        if (callStack == null) {
            callStack = new HashSet<>();
            CALL_STACK.set(callStack);
            isFirstInvocation = true;
        }

        String className = targetClass.getName();

        // 检查循环依赖
        if (callStack.contains(className)) {
            log.warn("Circular dependency detected: class '{}' is already in call stack: {}", className, callStack);
            return;
        }

        // 将当前类加入调用栈
        callStack.add(className);

        // 保存旧 group，用于 finally 恢复
        String oldGroup = GROUP_CONTEXT.get();
        GROUP_CONTEXT.set(effectiveGroup);

        try {
            // 获取或创建执行器
            CacheKey cacheKey = new CacheKey(targetClass, effectiveGroup);
            JoinItemsExecutor executor = cache.computeIfAbsent(cacheKey, k -> {
                log.debug("Creating JoinItemsExecutor for class: {}, group: {}", targetClass.getSimpleName(), effectiveGroup);
                return createJoinExecutorGroup(targetClass, effectiveGroup);
            });

            // 执行填充
            log.debug("Executing JoinItemsExecutor for {} records", data.size());
            executor.execute(data);

        } catch (Exception e) {
            log.error("Error during joinByMemory for class: {}, group: {}", targetClass.getSimpleName(), effectiveGroup, e);
            throw new RuntimeException("Failed to execute joinByMemory", e);
        } finally {
            // === 清理资源 ===
            // 1. 从调用栈移除当前类
            callStack.remove(className);

            // 2. 恢复 group 上下文
            if (oldGroup != null) {
                GROUP_CONTEXT.set(oldGroup);
            } else {
                GROUP_CONTEXT.remove();
            }

            // 3. 如果是本次调用链的入口，且栈已空，清理 ThreadLocal
            if (isFirstInvocation) {
                CALL_STACK.remove();
                // GROUP_CONTEXT 已在上面 remove() 或 set(old)，无需重复
            }

            log.debug("Completed joinByMemory for class: {}, group: {}", targetClass.getSimpleName(), effectiveGroup);
        }
    }

    @Override
    public <T> void register(Class<T> targetClass, String group) {
        if (targetClass == null) {
            throw new IllegalArgumentException("targetClass cannot be null");
        }
        CacheKey key = new CacheKey(targetClass, group);
        cache.computeIfAbsent(key, k -> {
            log.debug("Registering JoinItemsExecutor for class: {}, group: {}", targetClass.getSimpleName(), group);
            return createJoinExecutorGroup(targetClass, group);
        });
    }

    @Override
    public <T> void register(Class<T> targetClass) {
        register(targetClass, null);
    }

    /**
     * 创建 JoinItemsExecutor 实例
     */
    private JoinItemsExecutor createJoinExecutorGroup(Class<?> targetClass, String group) {
        return joinItemsExecutorFactory.createFor(targetClass, group);
    }

    /**
     * 缓存 Key：用于唯一标识一个 JoinItemsExecutor
     * 使用类名（String）而非 Class 对象，避免类加载器隔离问题
     */
    private static class CacheKey {
        private final String className;
        private final String group;

        public CacheKey(Class<?> clazz, String group) {
            this.className = clazz.getName();
            this.group = group;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof CacheKey)) return false;
            CacheKey cacheKey = (CacheKey) o;
            return Objects.equals(className, cacheKey.className) &&
                    Objects.equals(group, cacheKey.group);
        }

        @Override
        public int hashCode() {
            return Objects.hash(className, group);
        }

        @Override
        public String toString() {
            return "CacheKey{" +
                    "class='" + className + '\'' +
                    ", group='" + group + '\'' +
                    '}';
        }
    }
}